package com.fly.flowdemo.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import com.fly.flowdemo.R;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with Android Studio.
 * Package_Name：com.fly.textimagedemo
 * Project_Name：TextImageDemo
 * User：郭鹏飞
 * Date：2015/12/8
 * Email：love518420@foxmail.com
 * Description：
 */
public class FlowLayout extends ViewGroup {

    private Map<Integer, List<View>> views; // 所有的子view
    private List<View> lineViews; // 每一行的view
    private List<Integer> lineHeights; //记录所有行高
    private List<Integer> lineWidths; // 记录行宽
    private int index = 0; // 行索引从0开始

    // 行间距 控件水平间距
    private int lineSpace = 0, weightLevelSpace = 0;

    protected Context context;

    public FlowLayout(Context context) {
        this(context, null);
    }

    public FlowLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        this.context = context;
        // 解析自定义属性
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.FlowLayout, defStyleAttr, 0);
        int count = typedArray.getIndexCount();
        for (int i = 0; i < count; i++) {
            int type = typedArray.getIndex(i);
            switch (type) {
                case R.styleable.FlowLayout_lineSpace:
                    lineSpace = typedArray.getDimensionPixelOffset(type, lineSpace);
                    break;
                case R.styleable.FlowLayout_weightLevelSpace:
                    weightLevelSpace = typedArray.getDimensionPixelOffset(type, weightLevelSpace);
                    break;
                default:
                    break;
            }
        }
        typedArray.recycle();

        views = new HashMap<>();
        lineViews = new ArrayList<>();
        lineHeights = new ArrayList<>();
        lineWidths = new ArrayList<>();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 得到宽高的测量值和测量模式
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        // wrap_content 测量模式下的当前布局高度
        int height = 0;

        int lineWidth = 0; // 每一行的宽度
        int lineHeight = 0; // 每一行的高度

        // 重置索引
        index = 0;

        // 清空数据
        views.clear();
        lineViews.clear();
        lineHeights.clear();
        lineWidths.clear();

        // 遍历子view
        for (int i = 0; i < getChildCount(); i++) {
            // 得到当前索引下的子view
            View childView = getChildAt(i);
            // View.GONE 该模式下子view不可见不占据空间不需要计算
            if (childView.getVisibility() == View.GONE) {
                continue;
            }
            // 测量子view
            measureChild(childView, widthMeasureSpec, heightMeasureSpec);
            // 得到子view占据的宽高
            int childWidth = childView.getMeasuredWidth();
            int childHeight = childView.getMeasuredHeight();

            // 判断是否换行
            if (lineWidth + childWidth > widthSize - getPaddingLeft() - getPaddingRight()) {
                // 换行
                lineWidth = lineWidth - weightLevelSpace; // 减去最后多算的一个控件间距
                lineWidths.add(lineWidth);
//                width = Math.max(lineWidth, childWidth); // 设置布局宽为最大的行宽 （换行之前的所有行）
                lineWidth = childWidth + weightLevelSpace; // 重置行宽（当前行）
                height += lineHeight; //叠加行高（上一行）
                views.put(index++, lineViews); // 添加上一行的view
                lineViews = new ArrayList<>(); // 新建一个集合存放每一行的子view 不可以用clear
                lineViews.add(childView); // 添加当前行的第一个view
                lineHeights.add(lineHeight); //添加上一行的行高
                lineHeight = childHeight; // 设置当前的行高为第一个子view的高度
            } else {
                // 不换行
                lineWidth += (childWidth + weightLevelSpace); // 叠加（控件间距）得到当前的行宽 控件间距
                lineHeight = Math.max(lineHeight, childHeight); // 当前行最大子view高度设置为当前的行高
                lineViews.add(childView); // 添加view
            }
            // 处理最后一个控件的时候尺寸的计算
            if (i == getChildCount() - 1) {
                lineWidth -= weightLevelSpace;
                lineWidths.add(lineWidth);
//                width = Math.max(lineWidth, childWidth); // 设置布局宽为最大的行宽
                height += lineHeight; //叠加行高（当前行）
                /*
                * 思考
                * 如果最后一个子view需要换行，这height 叠加了上一行的行高，width计算的是上一行之前所有行
                * 没有对当前行进行计算
                * 如果最后一个子view不需要换行，height 没有叠加当前行行高，width没有计算当前行的行宽
                * 所以需要处理最后一个子view
                * */
            }
        }

        // 添加当前行
        views.put(index, lineViews); // 添加当前行的view
        lineHeights.add(lineHeight); // 添加当前行的行高

        height += (index) * lineSpace; // 添加行间距

        int maxLineWidth = getMaxLineWidth(lineWidths); // 得到最大的行宽

        setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ?
                widthSize : Math.min(widthSize, maxLineWidth)
                , heightMode == MeasureSpec.EXACTLY ?
                heightSize + (index) * lineSpace :
                Math.min(heightSize + (index) * lineSpace, height + getPaddingBottom() + getPaddingTop()));

    }

    /**
     * 得到最大的行宽
     *
     * @param lineHeights 行宽集合
     * @return 最大的行宽
     */
    private int getMaxLineWidth(List<Integer> lineHeights) {
        if (lineHeights.isEmpty()) {
            throw new NullPointerException("行宽集合为空");
        }
        int max = lineHeights.get(0);
        for (int i = 1; i < lineHeights.size() - 1; i++) {
            if (max < lineHeights.get(i)) {
                max = lineHeights.get(i);
            }
        }
        return max;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // 设置布局的起始位置
        int left = getPaddingLeft();
        int top = getPaddingTop();
        // 遍历行
        for (int i = 0; i <= index; i++) {
            // 遍历每行
            for (int j = 0; j < views.get(i).size(); j++) {
                // 得到当前索引下的子view
                View childView = views.get(i).get(j);
                // View.GONE 该模式下的子view不需要布局
                if (childView.getVisibility() == View.GONE) {
                    continue;
                }
                // 布局
                int cl = left;
                int cr = cl + childView.getMeasuredWidth();
                int cb = top + childView.getMeasuredHeight();
                childView.layout(cl, top, cr, cb);
                // 设置下一个子view的起始位置 当前的子view的左边的位置+控件之间的间距
                left = cr + weightLevelSpace;
            }

            // 换行时 重置布局位置
            left = getPaddingLeft();
            top += (lineHeights.get(i) + lineSpace);

        }
    }

}
